package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @GuiGuCache(prefix = "albumStat:info:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        return albumInfoMapper.selectAlbumStat(albumId);
    }

    @Override
    public List<AlbumAttributeValue> findAlbumAttributeValue(Long albumId) {
        //	AlbumAttributeValue 这个对象中的名称不需要赋值. 只需要获取到 attribute_id value_id
        return albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        //	select * from album_info where user_id = ? order by id desc limit 20;
        return albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).orderByDesc(AlbumInfo::getId).last(" limit 20"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfoById(Long albumId, AlbumInfoVo albumInfoVo) {
        //	album_info
        AlbumInfo albumInfo = new AlbumInfo();
        //	属性拷贝：
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setId(albumId);
        this.albumInfoMapper.updateById(albumInfo);

        //	album_attribute_value
        //	先删除，再新增
        this.albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //	获取前端传递的数据
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //	判断
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            //	循环遍历
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //	创建对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //	赋值：
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                //	循环执行多次insert 语句！改为批量插入！
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        //	判断：
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //	上架 发送的内容是由
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);
        } else {
            //	下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
        }

    }

    @Override
    @GuiGuCache(prefix = "album:info:")
    public AlbumInfo getAlbumInfo(Long albumId) {
        //	1.	查询数据的时候，先查询缓存！
        //	定义一个缓存的key=album:info:albumId;
        //        AlbumInfo albumInfo = getByRedisson(albumId);
        //        if (albumInfo != null) return albumInfo;
        //  数据库兜底.
        return getInfoDB(albumId);

    }

    @Nullable
    private AlbumInfo getByRedisson(Long albumId) {
        String key = RedisConstant.ALBUM_INFO_PREFIX + albumId;
        try {
            //	什么情况下选中hash，或字符串！
            AlbumInfo albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(key);
            //	判断缓存中是否有数据
            if (null == albumInfo) {
                //	缓存中为空！查询数据库. 声明一个锁的key
                String locKey = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
                //	获取到锁对象。
                RLock lock = redissonClient.getLock(locKey);
                //	上锁
                lock.lock();
                try {
                    //	查询数据库之前，再查询一次缓存.
                    albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(key);
                    //	如何缓存中有数据直接返回.
                    if (null != albumInfo) {
                        return albumInfo;
                    }
                    //	业务逻辑
                    albumInfo = this.getInfoDB(albumId);
                    System.out.println("查询数据库");
                    //	从数据库获取的数据值为空.
                    if (null == albumInfo) {
                        //	存储空对象
                        this.redisTemplate.opsForValue().set(key, new AlbumInfo(), RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        return new AlbumInfo();
                    }
                    //	将真实数据存储到缓存
                    this.redisTemplate.opsForValue().set(key, albumInfo, RedisConstant.ALBUM_TIMEOUT, TimeUnit.DAYS);
                    return albumInfo;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    //  new ReentrantLock().unlock();
                    //	解锁处理
                    lock.unlock();
                }
            }else {
                System.out.println("走了缓存.");
                //  返回数据
                return albumInfo;
            }
        } catch (RuntimeException e) {
            //  sendMsg("服务器挂了.");
            log.error("出现了异常"+e.getMessage());
        }
        return null;
    }

    @Nullable
    private AlbumInfo getInfoDB(Long albumId) {
        //	获取专辑对象
        AlbumInfo albumInfo = this.getById(albumId);
        //	给专辑对象赋值标签集合数据
        if (null != albumInfo) {
            //	select * from album_attribute_value where album_id = ?;
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)));
        }
        //	返回数据
        return albumInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfoById(Long albumId) {
        //	album_info album_attribute_value album_stat
        //	物理删除 delete from table where id = ?  逻辑删除 update album_info set is_deleted = 1 where id = ?;
        //	变为逻辑删除！
        albumInfoMapper.deleteById(albumId);
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));

        //	上架 发送的内容是由
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {
        //	组装数据：本质是给AlbumListVo赋值
        return albumInfoMapper.selectUserAlbumPage(albumListVoPage, albumInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
		/*
			album_attribute_value
			album_info
			album_stat -- 初始化！随机初始值！
		 */
        AlbumInfo albumInfo = new AlbumInfo();
        //	给对象赋值
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //	user_id:
        albumInfo.setUserId(userId);
        //	tracks_for_free免费试听集数
        if (!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
            albumInfo.setTracksForFree(5);
        }
        //	status 审核状态
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);

        //	保存数据
        albumInfoMapper.insert(albumInfo);

        //	album_attribute_value
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //	判断
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            //	循环遍历
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //	创建对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //	赋值：
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                //	循环执行多次insert 语句！改为批量插入！
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        //	album_stat
        saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
        saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
        saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
        saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);

        //	上架
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //	上架 发送的内容是由
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumStat(Long albumId, String statPlay) {
        //	创建对象
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statPlay);
        albumStat.setStatNum(new Random().nextInt(100));
        albumStatMapper.insert(albumStat);
    }
}
